package segimasat.partition.integer;


import segimasat.image.integer.RGB;
import segimasat.image.integer.GRAYx4_to_RGBx2;
import segimasat.image.integer.StackRGB;
import segimasat.image.integer.GRAYx3_to_RGBx1;
import ij.ImagePlus;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.ListIterator;
import javax.swing.JOptionPane;
import segimasat.image.Image;
import segimasat.image.Image8;
import segimasat.pixel.integer.*;
import segimasat.partition.Neighborhood;
import segimasat.partition.Settings;
import segimasat.pixel.PixelSum;


public class Partition8 extends segimasat.partition.Partition{
    public Image8 f;

    public Partition8(Image f, int alpha, int omega, double ci){
        this.f = (Image8)f;
        this.alpha = alpha;
        this.omega = omega;
        this.ci = ci;
        String tittle = "ALPHA = " + alpha + ", OMEGA = " + omega;
        if (f.impl.getStackSize() == 3 && f.impl.getType() == ImagePlus.GRAY8){
            Object[] options = {"Yes", "No"};
            int n = JOptionPane.showOptionDialog(null,
                "Would you like to see the partition as one output RGB image?",
                "Question", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, options[0]);
            if (n == 0){
                this.f = new GRAYx3_to_RGBx1(f.impl);
                this.out = new RGB(f.impr.getWidth(), f.impr.getHeight(), tittle);
                return;
            }
        }
        if (f.impl.getStackSize() == 4 && f.impl.getType() == ImagePlus.GRAY8){
            Object[] options = {"Yes", "No"};
            int n = JOptionPane.showOptionDialog(null,
                "Would you like to see the partition as two output RGB images? (RGB + IRGB)",
                "Question", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, options[0]);
            if (n == 0){
                this.f = new GRAYx4_to_RGBx2(f.impl);
                this.out = new StackRGB(f.impr.getWidth(), f.impr.getHeight(), 2, tittle);
                return;
            }
        }
        if (f.impl.getStackSize() == 1)
            this.out = new RGB(f.impr.getWidth(), f.impr.getHeight(), tittle);
        else if (f.impl.getStackSize() > 1)
            this.out = new StackRGB(f.impr.getWidth(), f.impr.getHeight(), f.impl.getStackSize(), tittle);
    }

    public void makeRegions(){
        Neighborhood nbh = new Neighborhood(f.impr.getWidth(), f.impr.getHeight());
        int n = f.impr.getHeight() * f.impr.getWidth();
        Queue PQueue = new Queue(Settings.MAX_ALPHA + 1);
        components = new ArrayList<Component8>();
        lbl = new int[n];
        int[] rl = new int[n];
        int lblval = 0;
        for (int i = 0; i < n; i++){
            lbl[i] = -1;
            rl[i] = Integer.MAX_VALUE;
        }
        for (int p = 0; p < n; p++){
            if (lbl[p] == -1){
                PixelSum lblColor = f.newPixelFloat();
                LinkedList<Integer> stack = new LinkedList<Integer>();
                ListIterator<Integer> it = stack.listIterator();
                PixelValue8 mincc = f.getPixel(p);
                PixelValue8 maxcc = f.getPixel(p);
                int rlcrt = alpha;
                int rcrt = 0;
                int edges = 0;
                int edgesOK = 0;
                PQueue.add(p, 0);
                while (! PQueue.isEmpty()){
                    PixelPriority8 datum = PQueue.remove(rcrt);
                    // Añadido al algoritmo original: si el pixel ya fue visitado, no lo vuelve a visitar
                    if (rl[datum.p] == -1)
                        continue;
                    if (lbl[datum.p] != -1)
                        continue;
                    if (datum.prio > rcrt){
                        while (it.hasPrevious()){
                            int r = it.previous();
                            lbl[r] = lblval;
                            lblColor.add(f.getPixel(r));
                        }
                        rcrt = datum.prio;
                        if (lbl[datum.p] != -1)
                            continue;
                    }
                    it.add(datum.p);
                    // Añadido al algoritmo original: el pixel se pone a -1 en rl, para que no lo visite mas
                    rl[datum.p] = -1;
                    PixelValue8 fp = f.getPixel(datum.p);
                    mincc.checkIsLowerThan(fp);
                    maxcc.checkIsGreaterThan(fp);
                    if (omega < maxcc.rangeNoAbs(mincc) || (rcrt > rlcrt)){
                        while (! PQueue.isEmpty())
                            rl[PQueue.remove().p] = Integer.MAX_VALUE;
                        while(it.hasPrevious()){
                            rl[it.previous()] = Integer.MAX_VALUE;
                            it.remove();
                        }
                        break;
                    }
                    for (int z = 0; z < Neighborhood.NEIGHBORS; z++){
                        Integer q = nbh.getNeighbor(datum.p, z);
                        if (q == null) continue; // No hay vecino, está en un borde de la imagen.
                        int rlval = f.getPixel(q).range(f.getPixel(datum.p));
                        if ((lbl[q] != -1) && (lbl[q] != lblval) && (rlcrt >= rlval)){
                            //rlcrt = rlval; // Esto es segun el algoritmo original, pero 99% seguro que esta mal
                            rlcrt = rlval - 1; //
                            if (rcrt > rlcrt){
                                while (! PQueue.isEmpty())
                                    rl[PQueue.remove().p] = Integer.MAX_VALUE;
                                while(it.hasPrevious()){
                                    rl[it.previous()] = Integer.MAX_VALUE;
                                    it.remove();
                                }
                                break;
                            }
                        }
                        else if ((rlval <= rlcrt) && (rlval < rl[q])){
                            rl[q] = rlval;
                            PQueue.add(q, rlval);
                        }
                    }
                } // Fin del while
                while (it.hasPrevious()){
                    int r = it.previous();
                    lbl[r] = lblval;
                    lblColor.add(f.getPixel(r));
                }
                lblval++;

                Component8 comp = new Component8(stack, lblColor, rcrt);
                components.add(comp);
                colourComponent(comp);
            }
        }
    }

    /*
    public void colourComponent(Component comp){
        ListIterator<Integer> it = comp.pixels.listIterator();
        PixelValue mincc = f.newPixelValue(Integer.MAX_VALUE);
        PixelValue maxcc = f.newPixelValue(0);
        while (it.hasNext()){
            int p = it.next();
            out.putPixel(p, comp.color.getRGB());
            PixelValue fp = f.getPixel(p);
            mincc.checkIsLowerThan(fp);
            maxcc.checkIsGreaterThan(fp);
        }
        out.impl.updateAndDraw();
        comp.min = mincc;
        comp.max = maxcc;
    }

    public void colourComponent(Component comp, PixelValue color){
        ListIterator<Integer> it = comp.pixels.listIterator();
        while (it.hasNext()){
            int p = it.next();
            out.putPixel(p, color.getRGB());
        }
        out.impl.updateAndDraw();
    }
    */

    public void colourComponentFirstTime(segimasat.partition.Component comp){
        ListIterator<Integer> it = comp.pixels.listIterator();
        PixelValue8 mincc = f.newPixelValue(Integer.MAX_VALUE);
        PixelValue8 maxcc = f.newPixelValue(0);
        while (it.hasNext()){
            int p = it.next();
            out.putPixel(p, ((Component8)comp).color.getRGB());
            PixelValue8 fp = f.getPixel(p);
            mincc.checkIsLowerThan(fp);
            maxcc.checkIsGreaterThan(fp);
        }
        out.impl.updateAndDraw();
        ((Component8)comp).min = mincc;
        ((Component8)comp).max = maxcc;
    }

    public void colourComponent(segimasat.partition.Component comp){
        comp = (Component8) comp;
        ListIterator<Integer> it = comp.pixels.listIterator();
        while (it.hasNext()){
            int p = it.next();
            out.putPixel(p, ((Component8)comp).color.getRGB());
        }
        out.impl.updateAndDraw();
    }

    public void colourComponent(segimasat.partition.Component comp, Object color){
        ListIterator<Integer> it = comp.pixels.listIterator();
        while (it.hasNext()){
            int p = it.next();
            out.putPixel(p, ((PixelValue8)color).getRGB());
        }
        out.impl.updateAndDraw();
    }



    @Override
    public String getColorString(int pixel) {
        throw new UnsupportedOperationException("Not supported yet.");
    }



}